﻿
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace weigh
{
    /// <summary>
    ///
    /// </summary>
    public class SerialCommunication
    {
        public delegate void EventHandle(byte[] readBuffer);
        public event EventHandle DataReceived;

        public SerialPort serialPort;
        Thread thread;
        volatile bool _keepReading;

        private List<byte> buffer = new List<byte>(4096);

        public SerialCommunication()
        {
            serialPort = new SerialPort();
            thread = null;
            _keepReading = false;
        }

        public bool IsOpen
        {
            get
            {
                return serialPort.IsOpen;
            }
        }

        private void StartReading()
        {
            if (!_keepReading)
            {
                _keepReading = true;
                thread = new Thread(new ThreadStart(ReadPort));
                thread.Start();
            }
        }

        private void StopReading()
        {
            if (_keepReading)
            {
                _keepReading = false;
                thread.Join();
                thread = null;
            }
        }

        private void ReadPort()
        {
            while (_keepReading)
            {
                if (!serialPort.IsOpen)
                {
                    continue;
                }

                int count = serialPort.BytesToRead;

                if (count < 7)
                {
                    continue;
                }


                byte[] readBuffer = new byte[count];
                try
                {
                    Application.DoEvents();
                    serialPort.Read(readBuffer, 0, count);

                    buffer.AddRange(readBuffer);

                    this.clearByte();
                    
                    //int len = readBuffer[1];
                    if (buffer.Count < 12)
                    {
                        //数据未接收完整跳出循环
                        continue;
                    }

                    byte[] outBuffer = new byte[12];
                    //得到完整的数据，复制到readBuffer中   
                    buffer.CopyTo(0, outBuffer, 0, 12);
                    //从缓冲区中清除
                    buffer.RemoveRange(0, 12);

                    //触发外部处理接收消息事件

                    if (DataReceived != null)
                        DataReceived(outBuffer);
                    Thread.Sleep(200);
                }
                catch (TimeoutException e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }

        // 清理不是标志位的数据
        private void clearByte()
        {
            int index = 0;

            int flag = 0;

            int receiveIndex = 0;

            for(int i = 0; i < this.buffer.Count; i++)
            {

                index = i + 1;

                if (index >= this.buffer.Count)
                {
                    break;
                }
                //至少包含标头(1字节),长度(1字节),校验位(2字节)等等
                //2.1 查找数据标记头           
                if (0x02 == this.buffer[i] && 0x2B == this.buffer[i + 1]) //传输数据有帧头，用于判断      
                {
                    // 找到标志位
                    receiveIndex = i;

                    flag = 18;

                    break;
                }
            }

            if (0 == flag)
            {
                // 没有找到标志位，数据无效
                this.buffer.Clear();

                return;
            }

            this.buffer.RemoveRange(0, receiveIndex);


        }

        public void Open()
        {
            Close();
            serialPort.Open();
            if (serialPort.IsOpen)
            {
                StartReading();
            }
            else
            {
                MessageBox.Show("串口打开失败！");
            }
        }

        public void Close()
        {
            StopReading();
            serialPort.Close();
        }

        public void WritePort(byte[] send, int offSet, int count)
        {
            if (IsOpen)
            {
                serialPort.Write(send, offSet, count);
            }
        }
    }
}